﻿using System;

namespace Borg
{
    public abstract class TextLoggerBase : ILogger
    {
        private readonly ILogFormatter _formatter;
        private Runtime _runtime;

        protected TextLoggerBase()
            : this(new LogFormatter())
        { }

        protected TextLoggerBase(LogFormatter formatter)
        {
            if (formatter == null)
                throw new ArgumentNullException("formatter");
            
            _formatter = formatter;
        }

        ~TextLoggerBase()
        {
            Dispose();
        }

        public virtual void Init(Runtime runtime)
        {
            _runtime = runtime;
        }

        public virtual void Dispose()
        { }

        public void LogContractAdded(ContractEventArgs args)
        {
            Log(_formatter.FormatContractAdded(this, args.Contract));

            foreach (var slotDef in args.Contract.SlotDefinitions)
                Log(_formatter.FormatSlotDefinitionAdded(this, slotDef));
        }

        public void LogContractRemoved(ContractEventArgs args)
        {
            foreach (var slotDef in args.Contract.SlotDefinitions)
                Log(_formatter.FormatSlotDefinitionRemoved(this, slotDef));
            
            Log(_formatter.FormatContractRemoved(this, args.Contract));
        }

        public void LogPluginAdded(PluginEventArgs args)
        {
            Log(_formatter.FormatPluginAdded(this, args.Plugin));
            
            foreach (var extensionType in args.Plugin.ExtensionTypes)
            {
                Log(_formatter.FormatExtensionTypeAdded(this, extensionType));
                
                foreach (var plugType in extensionType.PlugTypes)
                    Log(_formatter.FormatPlugTypeAdded(this, plugType));
                
                foreach (var slotType in extensionType.SlotTypes)
                    Log(_formatter.FormatSlotTypeAdded(this, slotType));
            }
        }

        public void LogPluginRemoved(PluginEventArgs args)
        {
            foreach (var extensionType in args.Plugin.ExtensionTypes)
            {
                foreach (var slotType in extensionType.SlotTypes)
                    Log(_formatter.FormatSlotTypeRemoved(this, slotType));
                
                foreach (var plugType in extensionType.PlugTypes)
                    Log(_formatter.FormatPlugTypeRemoved(this, plugType));
                
                Log(_formatter.FormatExtensionTypeRemoved(this, extensionType));
            }
            
            Log(_formatter.FormatPluginRemoved(this, args.Plugin));
        }

        public void LogUnhandledException(ExceptionEventArgs args)
        {
            Log(
                _formatter.FormatUnhandledException(
                    this,
                    args.Exception,
                    _runtime.VerbosityLevel == VerbosityLevel.Diagnostic));
        }

        public void LogCreated(ExtensionEventArgs args)
        {
            Log(_formatter.FormatCreated(this, args.Extension));
        }

        public void LogActivated(ExtensionEventArgs args)
        {
            Log(_formatter.FormatActivated(this, args.Extension));
        }

        public void LogDeactivated(ExtensionEventArgs args)
        {
            Log(_formatter.FormatDeactivated(this, args.Extension));
        }

        public void LogDestroyed(ExtensionEventArgs args)
        {
            Log(_formatter.FormatDestroyed(this, args.Extension));
        }

        public void LogOpened(SlotEventArgs args)
        {
            Log(_formatter.FormatOpened(this, args.Slot));
        }

        public void LogClosed(SlotEventArgs args)
        {
            Log(_formatter.FormatClosed(this, args.Slot));
        }

        public void LogPlugged(CompositionEventArgs args)
        {
            Log(_formatter.FormatPlugged(this, args.Slot, args.Plug));
        }

        public void LogUnplugged(CompositionEventArgs args)
        {
            Log(_formatter.FormatUnplugged(this, args.Slot, args.Plug));
        }

        public void LogTagged(TagEventArgs args)
        {
            Log(_formatter.FormatTagged(this, args.Tag.Slot, args.Tag.Plug, args.Tag.Name));
        }

        public void LogUntagged(TagEventArgs args)
        {
            Log(_formatter.FormatUntagged(this, args.Tag.Slot, args.Tag.Plug, args.Tag.Name));
        }

        public abstract void Log(LogArgs args);

        public void Log(CustomLogArgs args)
        {
            Log(args.ToLogArgs());
        }
    }
}
